package com.ytoglobal.overseas.address.platform.service.impl;

import com.alibaba.fastjson.JSON;
import com.mayabot.nlp.utils.CharNormUtils;
import com.ytoglobal.overseas.address.platform.dao.ElasticsearchRestDao;
import com.ytoglobal.overseas.address.platform.model.request.AddressRequest;
import com.ytoglobal.overseas.address.platform.model.response.AddressMessageResponse;
import com.ytoglobal.overseas.address.platform.service.AddressMessageService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class AddressMessageServiceImpl implements AddressMessageService {

    @Autowired
    private ElasticsearchRestDao elasticsearchRestDao;

    private final static String ADDRESS_INDEX = "cloud_address_resolve";

    private final static String ADDRESS_INDEX_TYPE = "cloud_address_resolve_type";

    @Override
    public AddressMessageResponse parseAddress(AddressRequest addressRequest) {
        Map<String, Object> parsedDataMap = new HashMap<>();
        String originAddress = CharNormUtils.convert(addressRequest.getAddress());
        //1.识别省
        parseProvince(originAddress, addressRequest, parsedDataMap);
        //2.识别名称
        String clearProvinceAddress = parseName(originAddress, parsedDataMap);
        //3.识别市
        parseCity(clearProvinceAddress, addressRequest, parsedDataMap);
        //4.原始地址截取掉市，方便下一级 区/县 查询
        String clearCityAddress = clearCity(clearProvinceAddress, parsedDataMap);
        //5.识别区
        parseDistrict(clearCityAddress, addressRequest, parsedDataMap);
        //6.删除区信息，方便下一级 乡/镇 查询
        String clearDistrictAddress = clearDistrict(clearCityAddress, parsedDataMap);
        //6.识别乡/镇
        parseTown(clearDistrictAddress, addressRequest, parsedDataMap);
        //7.获取详细地址
        parsedDataMap.put("detail", clearTownAddress(clearDistrictAddress, parsedDataMap));

        //8.json转对象
        AddressMessageResponse addressMessageResponse = JSON.parseObject(JSON.toJSONString(parsedDataMap), AddressMessageResponse.class);
        addressMessageResponse.setOriginAdd(addressRequest.getAddress());

        return addressMessageResponse;
    }

    @Override
    public void initAddressMetaData() throws Exception {
        String file = this.getClass().getClassLoader().getResource("city_info.txt").getFile();
        try {
            FileReader fileReader = new FileReader(file);
            BufferedReader bf = new BufferedReader(fileReader);
            String str;
            // 按行读取字符串
            List<Map<String, Object>> list = new ArrayList<>(45000);
            elasticsearchRestDao.deleteIndex("cloud_address_resolve*");
            while ((str = bf.readLine()) != null) {
                String[] strArray = str.split("   ");
                if (strArray.length == 8) {
                    //省份
                    String provinceCode = strArray[0].trim();
                    String province = strArray[1].trim();
                    //城市
                    String cityCode = strArray[2].trim();
                    String city = strArray[3].trim();
                    //区县
                    String districtCode = strArray[4].trim();
                    String district = strArray[5].trim();
                    //乡镇
                    String townCode = strArray[6].trim();
                    String town = strArray[7].trim();

                    Map<String, Object> addressMap = new HashMap<>();
                    addressMap.put("country", "中国");
                    addressMap.put("country_code", 0);
                    addressMap.put("country_alias", "中华人民共和国#中国");

                    StringBuffer provinceBuf = new StringBuffer(province);
                    addressMap.put("province", province);
                    if (province.endsWith("省")) {
                        provinceBuf.append("#").append(province, 0, province.lastIndexOf("省"));
                    } else if (province.endsWith("市")) {
                        provinceBuf.append("#").append(province, 0, province.lastIndexOf("市"));
                    } else if (province.endsWith("自治区")) {
                        provinceBuf.append("#").append(province, 0, province.lastIndexOf("自治区"));
                    } else if (province.endsWith("壮族自治区")) {
                        provinceBuf.append("#").append(province, 0, province.lastIndexOf("壮族自治区"));
                    } else if (province.endsWith("维吾尔自治区")) {
                        provinceBuf.append("#").append(province, 0, province.lastIndexOf("维吾尔自治区"));
                    }
                    addressMap.put("province_code", provinceCode);
                    addressMap.put("province_alias", provinceBuf.toString());

                    addressMap.put("city", city);
                    addressMap.put("city_code", cityCode);
                    StringBuffer cityBuf = new StringBuffer(city);
                    if (city.endsWith("市")) {
                        cityBuf.append("#").append(city, 0, city.lastIndexOf("市"));
                    } else if (city.endsWith("地区")) {
                        cityBuf.append("#").append(city, 0, city.lastIndexOf("地区"));
                    } else if (city.endsWith("自治州")) {
                        cityBuf.append("#").append(city, 0, city.lastIndexOf("自治州"));
                    }
                    addressMap.put("city_alias", cityBuf.toString());
                    addressMap.put("district", district);
                    addressMap.put("district_code", districtCode);
                    StringBuffer districtBuf = new StringBuffer(district);
                    if (district.endsWith("县")) {
                        districtBuf.append("#").append(district, 0, district.lastIndexOf("县"));
                    } else if (district.endsWith("市")) {
                        districtBuf.append("#").append(district, 0, district.lastIndexOf("市"));
                    } else if (district.endsWith("区")) {
                        districtBuf.append("#").append(district, 0, district.lastIndexOf("区"));
                    }
                    if (district.equals("鄠邑区")) {
                        districtBuf.append("#").append("鄠邑区");
                        districtBuf.append("#").append("户县");
                        districtBuf.append("#").append("鄠县");
                    }
                    addressMap.put("district_alias", districtBuf.toString());

                    addressMap.put("town", town);
                    addressMap.put("town_code", townCode);
                    addressMap.put("town_alias", town);

                    addressMap.put("language", "zh-cn");
                    addressMap.put("create_time", "2019-11-18 15:00:00");
                    addressMap.put("update_time", "2019-11-18 15:00:00");
                    addressMap.put("is_deleted", 0);
                    list.add(addressMap);
                } else {
                    System.out.println("初始化地址元数据失败：" + str);
                }
            }
            elasticsearchRestDao.bulkAddDate("cloud_address_resolve_uat", "cloud_address_resolve_type", null, list);
            bf.close();
            fileReader.close();
        } catch (IOException e) {
            log.error("初始化地址字典库失败", e);
            throw new Exception("初始化失败");
        }
    }

    public void parseProvince(String originAddress, AddressRequest addressRequest, Map<String, Object> parsedDataMap) {
        BoolQueryBuilder finalQueryBuilder = QueryBuilders.boolQuery();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("province_alias", originAddress);
        finalQueryBuilder.must(matchQueryBuilder);

        String language = addressRequest.getLanguage();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("language", language);
        finalQueryBuilder.must(termQueryBuilder);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        String[] fetchField = {"province", "province_code", "country", "province_alias"};
        searchSourceBuilder.query(finalQueryBuilder).fetchSource(fetchField, null).size(1);

        Map<String, Object> parsedProvinceDataMap = elasticsearchRestDao.searchIndexForOneResult(ADDRESS_INDEX, ADDRESS_INDEX_TYPE, searchSourceBuilder);
        parsedDataMap.putAll(parsedProvinceDataMap);
    }

    private String parseName(String originAddress, Map<String, Object> parsedProvinceDataMap) {
        if (parsedProvinceDataMap.containsKey("province_alias")) {
            String provinceAlias = String.valueOf(parsedProvinceDataMap.get("province_alias"));
            for (String shortName : provinceAlias.split("#")) {
                int shortIndex = originAddress.indexOf(shortName);
                if (shortIndex > -1) {
                    // 如果省份不是第一位 在省份之前的字段识别为名称
                    if (shortIndex > 0) {
                        String name = originAddress.substring(0, shortIndex);
                        originAddress = originAddress.substring(shortIndex);
                        parsedProvinceDataMap.put("name", name);
                    }
                    originAddress = originAddress.substring(shortName.length());
                    break;
                }
            }
        }
        return originAddress;
    }

    private void parseCity(String originAddress, AddressRequest addressRequest, Map<String, Object> parsedProvinceDataMap) {
        BoolQueryBuilder finalQueryBuilder = QueryBuilders.boolQuery();

        String[] fetchField = {"city", "city_alias", "city_code"};
        if (parsedProvinceDataMap.containsKey("province")) {
            String province = String.valueOf(parsedProvinceDataMap.get("province"));
            TermQueryBuilder provinceQueryBuilder = QueryBuilders.termQuery("province", province);
            finalQueryBuilder.must(provinceQueryBuilder);
        } else {
            fetchField = new String[]{"city", "city_code", "city_alias", "province", "province_code", "country"};
        }

        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("city_alias", originAddress);
        finalQueryBuilder.must(matchQueryBuilder);

        String language = addressRequest.getLanguage();
        TermQueryBuilder langQueryBuilder = QueryBuilders.termQuery("language", language);
        finalQueryBuilder.must(langQueryBuilder);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(finalQueryBuilder).fetchSource(fetchField, null).size(1);

        Map<String, Object> parsedCityDataMap = elasticsearchRestDao.searchIndexForOneResult(ADDRESS_INDEX, ADDRESS_INDEX_TYPE, searchSourceBuilder);

        parsedProvinceDataMap.putAll(parsedCityDataMap);
    }

    private void parseDistrict(String originAddress, AddressRequest addressRequest, Map<String, Object> parsedProvinceDataMap) {
        BoolQueryBuilder finalQueryBuilder = QueryBuilders.boolQuery();

        String[] fetchField = {"district", "district_alias", "district_code"};
        if (parsedProvinceDataMap.containsKey("province")) {
            String province = String.valueOf(parsedProvinceDataMap.get("province"));
            TermQueryBuilder provinceQueryBuilder = QueryBuilders.termQuery("province", province);
            finalQueryBuilder.must(provinceQueryBuilder);
        } else {
            fetchField = new String[]{"province", "province_code", "district", "district_alias", "district_code"};
        }

        if (parsedProvinceDataMap.containsKey("city")) {
            String city = String.valueOf(parsedProvinceDataMap.get("city"));
            TermQueryBuilder cityQueryBuilder = QueryBuilders.termQuery("city", city);
            finalQueryBuilder.must(cityQueryBuilder);
        } else {
            fetchField = new String[]{"city", "city_code", "district", "district_code", "district_alias"};
        }

        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("district_alias", originAddress);
        finalQueryBuilder.must(matchQueryBuilder);

        String language = addressRequest.getLanguage();
        TermQueryBuilder langQueryBuilder = QueryBuilders.termQuery("language", language);
        finalQueryBuilder.must(langQueryBuilder);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.query(finalQueryBuilder).fetchSource(fetchField, null).size(1);

        Map<String, Object> parsedCityDataMap = elasticsearchRestDao.searchIndexForOneResult(ADDRESS_INDEX, ADDRESS_INDEX_TYPE, searchSourceBuilder);

        parsedProvinceDataMap.putAll(parsedCityDataMap);
    }

    private void parseTown(String clearDistrictAddress, AddressRequest addressRequest, Map<String, Object> parsedDataMap) {

        if (!parsedDataMap.containsKey("district")) {
            return;
        }

        String[] fetchField = {"town", "town_alias", "town_code"};

        BoolQueryBuilder finalQueryBuilder = QueryBuilders.boolQuery();
        String district = String.valueOf(parsedDataMap.get("district"));
        TermQueryBuilder districtBuilder = QueryBuilders.termQuery("district", district);
        finalQueryBuilder.must(districtBuilder);

        if (parsedDataMap.containsKey("province")) {
            String province = String.valueOf(parsedDataMap.get("province"));
            TermQueryBuilder provinceQueryBuilder = QueryBuilders.termQuery("province", province);
            finalQueryBuilder.must(provinceQueryBuilder);
        }

        if (parsedDataMap.containsKey("city")) {
            String city = String.valueOf(parsedDataMap.get("city"));
            TermQueryBuilder cityQueryBuilder = QueryBuilders.termQuery("city", city);
            finalQueryBuilder.must(cityQueryBuilder);
        }

        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("town_alias", clearDistrictAddress);
        finalQueryBuilder.must(matchQueryBuilder);

        String language = addressRequest.getLanguage();
        TermQueryBuilder langQueryBuilder = QueryBuilders.termQuery("language", language);
        finalQueryBuilder.must(langQueryBuilder);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(finalQueryBuilder).fetchSource(fetchField, null).size(1);

        Map<String, Object> parsedTownMap = elasticsearchRestDao.searchIndexForOneResult(ADDRESS_INDEX, ADDRESS_INDEX_TYPE, searchSourceBuilder);
        parsedDataMap.putAll(parsedTownMap);
    }

    private String clearCity(String originAddress, Map<String, Object> parsedCityDataMap) {
        if (parsedCityDataMap.containsKey("city")) {
            String cityAlias = String.valueOf(parsedCityDataMap.get("city_alias"));
            for (String shortName : cityAlias.split("#")) {
                int shortIndex = originAddress.indexOf(shortName);
                if (shortIndex > -1) {
                    // 如果市不是第一位,截取
                    if (shortIndex > 0) {
                        originAddress = originAddress.substring(shortIndex);
                    }
                    originAddress = originAddress.substring(shortName.length());
                    break;
                }
            }
        }
        return originAddress;
    }

    private String clearDistrict(String originAddress, Map<String, Object> parsedCityDataMap) {
        if (parsedCityDataMap.containsKey("district")) {
            String cityAlias = String.valueOf(parsedCityDataMap.get("district_alias"));
            for (String shortName : cityAlias.split("#")) {
                int shortIndex = originAddress.indexOf(shortName);
                if (shortIndex > -1) {
                    // 如果市不是第一位,截取
                    if (shortIndex > 0) {
                        originAddress = originAddress.substring(shortIndex);
                    }
                    originAddress = originAddress.substring(shortName.length());
                    break;
                }
            }
        }
        return originAddress;
    }

    private String clearTownAddress(String clearDistrictAddress, Map<String, Object> parsedDataMap) {
        if (parsedDataMap.containsKey("town")) {
            String cityAlias = String.valueOf(parsedDataMap.get("town_alias"));
            for (String shortName : cityAlias.split("#")) {
                int shortIndex = clearDistrictAddress.indexOf(shortName);
                if (shortIndex > -1) {
                    // 如果市不是第一位,截取
                    if (shortIndex > 0) {
                        clearDistrictAddress = clearDistrictAddress.substring(shortIndex);
                    }
                    clearDistrictAddress = clearDistrictAddress.substring(shortName.length());
                    break;
                }
            }
        }
        return clearDistrictAddress;
    }
}
